package com.ushahidi.android.app;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.Vector;

import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.ushahidi.android.app.ChangeLoc.MapMarker;
import com.ushahidi.android.app.ChangeLoc.OneTimeDeviceLocationListener;
import com.ushahidi.android.app.data.AddIncidentData;
import com.ushahidi.android.app.data.UshahidiDatabase;
import com.ushahidi.android.app.net.UshahidiHttpClient;
import com.ushahidi.android.app.util.Util;

public class ChangeLoc extends MapActivity {

	// Menu Numbers

	private static final int HOME = Menu.FIRST + 1;

	private static final int LIST_INCIDENT = Menu.FIRST + 2;

	private static final int INCIDENT_MAP = Menu.FIRST + 3;

	private static final int INCIDENT_REFRESH = Menu.FIRST + 4;

	private static final int SETTINGS = Menu.FIRST + 5;

	private static final int ABOUT = Menu.FIRST + 6;

	private static final int GOTOHOME = 0;

	private static final int MAP_INCIDENTS = 1;

	private static final int LIST_INCIDENTS = 2;

	private static final int REQUEST_CODE_SETTINGS = 3;

	private static final int REQUEST_CODE_ABOUT = 4;

	private TextView change_loc_TV;

	private EditText change_loc_ET;

	private Button findButton;

	private Button searchButton;

	private MapView mapView = null;

	private MapController mapController;

	private static double sLongitude;

	private static double sLatitude;

	private Geocoder mGc;

	private List<Address> mFoundAddresses;

	private Bundle mBundle;

	private String LocationName = "";

	private GeoPoint dropPin = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		setContentView(R.layout.change_loc_map);

		mFoundAddresses = new ArrayList<Address>();

		mGc = new Geocoder(this, Locale.US);
		// TODO OceanMaster, change this when internationalized.

		// load settings
		//UshahidiPref.loadSettings(ChangeLoc.this);

		initComponents();

		configureMap();
		readyLocationService();
		// on create, if in father activity, user have enter a location,
		// search the location
		if (change_loc_ET.getText().toString() != null) {
			setLocationBySearch(change_loc_ET.getText().toString());
		}
		// make sure current location and pick right detail level
	}

	protected void onDestroy() {

		unregisterListeners();
		super.onDestroy();
	}

	public void initComponents() {

		change_loc_TV = (TextView) findViewById(R.id.change_incident_loc);
		change_loc_ET = (EditText) findViewById(R.id.change_incident_location);
		findButton = (Button) findViewById(R.id.change_loc_button);
		searchButton = (Button) findViewById(R.id.search_loc);
		mapView = (MapView) findViewById(R.id.change_loc_map);
		mapView.setOnTouchListener(new View.OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				return mGestureDetector.onTouchEvent(event);
			}
		});
		mapView.setBuiltInZoomControls(true);
		this.initGestureDetector();
		

		mapController = mapView.getController();
		mBundle = new Bundle();
		mBundle = getIntent().getExtras();
		LocationName = mBundle.getString("locationName");
		if (LocationName != "" && !(LocationName.equals("Current Location")))
			change_loc_ET.setText(LocationName);

		searchButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				if (setLocationBySearch(change_loc_ET.getText().toString())) {
					LocationName = change_loc_ET.getText().toString();
				} else {
					LocationName = "";
					sLatitude = 0.0;
					sLongitude = 0.0;
				}
			}
		});

		findButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {

				Bundle myBundle = new Bundle();
				myBundle.putString("locationName", change_loc_ET.getText()
						.toString());
				myBundle.putString("Latitude", String.valueOf(sLatitude));
				myBundle.putString("Longitude", String.valueOf(sLongitude));
				// TODO will add a button later to return to father activity

				Intent intent = new Intent();
				intent.putExtras(myBundle);
				setResult(RESULT_OK, intent);
				// intent.setClass(ChangeLoc.this, IProvide.class);
				// startActivityForResult(intent, GOTOHOME);
				// setResult(RESULT_OK);
				finish();

				/*
				 * Intent intent = new Intent(); intent.putExtras(myBundle);
				 * intent.setClass(ChangeLoc.this, AddIncident.class);
				 * startActivityForResult(intent, GOTOHOME);
				 * setResult(RESULT_OK); finish();
				 */

			}
		});
	}

	// ------------------------
	// MENU STUFF
	// ------------------------

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenu.ContextMenuInfo menuInfo) {
		populateMenu(menu);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		populateMenu(menu);

		return (super.onCreateOptionsMenu(menu));
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		return (applyMenuChoice(item) || super.onOptionsItemSelected(item));
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {

		return (applyMenuChoice(item) || super.onContextItemSelected(item));
	}

	private void populateMenu(Menu menu) {
		// TODO save for later modify
		MenuItem i;

		i = menu.add(Menu.NONE, HOME, Menu.NONE, R.string.menu_home);
		i.setIcon(R.drawable.ushahidi_home);

		i = menu.add(Menu.NONE, LIST_INCIDENT, Menu.NONE,
				R.string.incident_list);
		i.setIcon(R.drawable.ushahidi_list);

		i = menu.add(Menu.NONE, INCIDENT_MAP, Menu.NONE,
				R.string.incident_menu_map);
		i.setIcon(R.drawable.ushahidi_map);

		i = menu.add(Menu.NONE, INCIDENT_REFRESH, Menu.NONE,
				R.string.incident_menu_refresh);
		i.setIcon(R.drawable.ushahidi_refresh);

		i = menu.add(Menu.NONE, SETTINGS, Menu.NONE, R.string.menu_settings);
		i.setIcon(R.drawable.ushahidi_settings);

		i = menu.add(Menu.NONE, ABOUT, Menu.NONE, R.string.menu_about);
		i.setIcon(R.drawable.ushahidi_about);

	}

	private boolean applyMenuChoice(MenuItem item) {
		Intent launchPreferencesIntent;
		switch (item.getItemId()) {

		case LIST_INCIDENT:
			launchPreferencesIntent = new Intent(ChangeLoc.this, IProvide.class);
			startActivityForResult(launchPreferencesIntent, LIST_INCIDENTS);
			setResult(RESULT_OK);
			return true;

		case INCIDENT_MAP:
			launchPreferencesIntent = new Intent(ChangeLoc.this,
					ListIncidents.class);
			startActivityForResult(launchPreferencesIntent, MAP_INCIDENTS);
			return true;

		case HOME:
			launchPreferencesIntent = new Intent(ChangeLoc.this, Ushahidi.class);
			startActivityForResult(launchPreferencesIntent, GOTOHOME);
			setResult(RESULT_OK);
			return true;

		case ABOUT:
			launchPreferencesIntent = new Intent(ChangeLoc.this, About.class);
			startActivityForResult(launchPreferencesIntent, REQUEST_CODE_ABOUT);
			setResult(RESULT_OK);
			return true;

		case SETTINGS:
			launchPreferencesIntent = new Intent().setClass(ChangeLoc.this,
					Settings.class);

			// Make it a subactivity so we know when it returns
			startActivityForResult(launchPreferencesIntent,
					REQUEST_CODE_SETTINGS);
			return true;

		}
		return false;
	}

	// ==========================
	// Gesture Detector
	// ==========================

	private GestureDetector mGestureDetector;
	private String locNameTxt = "";
	private MapMarker mapMarker = null;

	private void initGestureDetector() {
		mGestureDetector = new GestureDetector(
				new GestureDetector.SimpleOnGestureListener() {
					@Override
					public void onLongPress(MotionEvent event_p) {

						final int action = event_p.getAction();
						OverlayItem inDrag = null;
						dropPin = mapView.getProjection().fromPixels(
								(int) event_p.getX(), (int) event_p.getY());
						final int x = (int) event_p.getX();
						final int y = (int) event_p.getY();
						if (mapMarker != null) {
							List<OverlayItem> locations = mapMarker
									.getLocations();
							if (action == MotionEvent.ACTION_DOWN) {
								for (OverlayItem item : locations) {
									Point p = new Point(0, 0);
									mapView.getProjection().toPixels(
											item.getPoint(), p);
									if (!mapMarker.isHit(item, marker, x - p.x,
											y - p.y)) {
										inDrag = item;
										locations.remove(inDrag);
										GeoPoint myPlace = new GeoPoint(dropPin
												.getLatitudeE6(), dropPin
												.getLongitudeE6());
										locations.add(new OverlayItem(myPlace,
												" ", " "));
										mapMarker.repopulate(locations);
									}
								}
							}
						}
						else
						{
							List<OverlayItem> locations=new ArrayList<OverlayItem>();
							if (action == MotionEvent.ACTION_DOWN) {
								placeMarker(dropPin
										.getLatitudeE6(), dropPin
										.getLongitudeE6());
								/*
									Point p = new Point(0, 0);
									GeoPoint myPlace = new GeoPoint(dropPin
												.getLatitudeE6(), dropPin
												.getLongitudeE6());
									locations.add(new OverlayItem(myPlace,
												" ", " "));
									mapMarker.repopulate(locations);*/
									}

						}
						locNameTxt = dropPin.getLatitudeE6() / 10E5
								+ "," + dropPin.getLongitudeE6() / 10E5;
						sLongitude = dropPin.getLongitudeE6() / 10E5;
						sLatitude = dropPin.getLatitudeE6() / 10E5;
						change_loc_ET.setText(locNameTxt);
					}

					@Override
					public boolean onDoubleTap(MotionEvent e) {

						return false;
					}

					@Override
					public boolean onDown(MotionEvent e) {
						return false;
					}
				});
		mGestureDetector.setIsLongpressEnabled(true);

	}

	// =========================
	// Location Service
	// =========================
	LocationManager manager;
	long updateTimeMsec = 0;
	float updateDistance = 0;
	LocationProvider high;
	LocationProvider low;

	private OneTimeDeviceLocationListener high_listener = null;
	private OneTimeDeviceLocationListener low_listener = null;

	private void registerHighOneTimeListener() {
		high_listener = new OneTimeDeviceLocationListener();
		manager.requestLocationUpdates(high.getName(), updateTimeMsec,
				updateDistance, high_listener);
	}

	private void registerLowOneTimeListener() {
		low_listener = new OneTimeDeviceLocationListener();
		manager.requestLocationUpdates(low.getName(), updateTimeMsec,
				updateDistance, low_listener);
	}

	private void unregisterListeners() {
		if (high_listener != null) {
			manager.removeUpdates(high_listener);
			high_listener = null;
		}
		if (low_listener != null) {
			manager.removeUpdates(low_listener);
			low_listener = null;
		}
	}

	// Fetches the current location of the device.
	// create two different listeners, one for once, one for long
	// temporarily, periodical location service is not needed because
	// we are not following user
	private void readyLocationService() {
		// ===============================
		// ready one time location request
		// ===============================
		// listener = new OneTimeDeviceLocationListener();
		manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		// get low and high accuracy provider
		// this is tempararily changed, due to simulation
		// low = manager.getProvider(manager.getBestProvider(
		// Util.createCoarseCriteria(), true));
		// high = manager.getProvider(manager.getBestProvider(
		// Util.createFineCriteria(), true));

		// low = manager.getProvider(manager.NETWORK_PROVIDER);
		//high = manager.getProvider(manager.GPS_PROVIDER);

		// imediately register 2 one time service to update location
		//registerHighOneTimeListener();
		// registerLowOneTimeListener();
	}

	Drawable marker;

	private void configureMap() {
		Log.v("Oceanmaster", "Mapview BuiltInZoomControls On");

		marker = getResources().getDrawable(R.drawable.marker);
		marker.setBounds(0, 0, marker.getIntrinsicWidth(),
				marker.getIntrinsicHeight());

		mapView.getController().setZoom(16);// changed from 14 to 16
		mapView.setBuiltInZoomControls(true);
		// mapView.displayZoomControls(true);
	}

	private void placeMarker(int markerLatitude, int markerLongitude) {
		// TODO switch marker icons
		// TODO Can we optimized this by directly change exosting MapMarker. Not
		// sure yet
		this.mapMarker = new MapMarker(marker, markerLatitude, markerLongitude);
		mapView.getOverlays().add(mapMarker);
	}

	public GeoPoint getPoint(double lat, double lon) {
		return (new GeoPoint((int) (lat * 1000000.0), (int) (lon * 1000000.0)));
	}

	// Modified by OceanMaster, added updateText argument
	private void centerLocation(GeoPoint centerGeoPoint, boolean updateText) {
		mapController.animateTo(centerGeoPoint);
		sLatitude = centerGeoPoint.getLatitudeE6() / 1.0E6;
		sLongitude = centerGeoPoint.getLongitudeE6() / 1.0E6;

		// if (updateText)change_loc_ET.setText(getLocationFromLatLon(sLatitude,
		// sLongitude));
		placeMarker(centerGeoPoint.getLatitudeE6(),
				centerGeoPoint.getLongitudeE6());
	}

	private boolean setLocationBySearch(String search) {
		Log.v("Oceanmaster", "setLocationBySearch : " + search);
		if (search == null || search.length() == 0) {
			Util.showToast(ChangeLoc.this,
					"Please fill search field first to find location");
			return false;
		}
		try {
			List<Address> result = mGc.getFromLocationName(search, 1);
			if (result.size() <= 0) {
				Util.showToast(ChangeLoc.this, "No result found");
				return false;
			}

			Address location = result.get(0);

			sLatitude = location.getLatitude();
			sLongitude = location.getLongitude();

			centerLocation(getPoint(sLatitude, sLongitude), false);
			// change_loc_ET.setText(String.valueOf(sLatitude) + ", "
			// + String.valueOf(sLongitude));
			return true;

		} catch (IOException e) {
			Util.showToast(ChangeLoc.this,
					"Error occured while trying to search Location");
			return false;
		}
	}

	// get the real location name from the latitude and longitude.
	private String getLocationFromLatLon(double lat, double lon) {
		Log.v("Oceanmaster", "Location name service requested");
		try {
			Address address;
			mFoundAddresses = mGc.getFromLocation(lat, lon, 2);
			if (mFoundAddresses.size() > 0) {
				address = mFoundAddresses.get(0);
				return address.getSubAdminArea();
			} else {
				return "";
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	public class MapMarker extends ItemizedOverlay<OverlayItem> {

		private List<OverlayItem> locations = new ArrayList<OverlayItem>();

		private Drawable marker;

		private OverlayItem myOverlayItem;

		public MapMarker(Drawable defaultMarker, int LatitudeE6, int LongitudeE6) {
			super(defaultMarker);
			this.marker = defaultMarker;
			// create locations of interest
			GeoPoint myPlace = new GeoPoint(LatitudeE6, LongitudeE6);
			myOverlayItem = new OverlayItem(myPlace, " ", " ");
			locations.add(myOverlayItem);
			populate();

		}
		public MapMarker(Drawable defaultMarker) {
			super(defaultMarker);
			this.marker = defaultMarker;
			populate();

		}

		public void repopulate(List<OverlayItem> locations2) {
			// TODO Auto-generated method stub
			this.locations = locations2;
			this.populate();
		}

		public boolean isHit(OverlayItem item, Drawable marker2, int i, int j) {
			return hitTest(item, marker2, i, j);
		}

		public List<OverlayItem> getLocations() {
			return this.locations;
		}

		// Added by OceanMaster, not tested
		public void addLocation(int LatitudeE6, int LongitudeE6) {
			GeoPoint myPlace = new GeoPoint(LatitudeE6, LongitudeE6);
			myOverlayItem = new OverlayItem(myPlace, " ", " ");
			locations.add(myOverlayItem);
			populate();
		}

		@Override
		protected OverlayItem createItem(int i) {
			return locations.get(i);
		}

		@Override
		public int size() {
			return locations.size();
		}

		@Override
		public void draw(Canvas canvas, MapView mapView, boolean shadow) {
			super.draw(canvas, mapView, shadow);
			boundCenterBottom(marker);
		}

		@Override
		public boolean onTouchEvent(MotionEvent event, MapView mapView) {
			return mGestureDetector.onTouchEvent(event);
			// return false;
		}

	}

	// get the current location of the device/user
	public class OneTimeDeviceLocationListener implements LocationListener {
		OneTimeDeviceLocationListener() {
			super();
			Log.v("Oceanmaster", "new OneTimeListener Created");
		}

		public void onLocationChanged(Location location) {
			Log.v("Oceanmaster", "Location Changed");
			if (location != null) {
				manager.removeUpdates(OneTimeDeviceLocationListener.this);

				sLatitude = location.getLatitude();
				sLongitude = location.getLongitude();

				centerLocation(getPoint(sLatitude, sLongitude), true);

				// change_loc_ET.setText(String.valueOf(sLatitude) + ", "+
				// String.valueOf(sLongitude));

			}
		}

		public void onProviderDisabled(String provider) {
			Util.showToast(ChangeLoc.this, R.string.location_not_found);
			Log.v("Oceanmaster", "LocationProvider " + provider.toString()
					+ " Disabled");
		}

		public void onProviderEnabled(String provider) {
			Log.v("Oceanmaster", "LocationProvider " + provider.toString()
					+ " Enabled");
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {

		}
	}
 
}
	